package com.util.xls;

import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.util.HSSFColor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @auther carter
 * create time    2018-06-20
 */
public class XlsUtils {

    private static final Logger logger = LoggerFactory.getLogger(XlsUtils.class);

    /**
     * 不指定列头，按照实体的自然顺序展示
     * @param fileName  保存的xls文件名
     * @param response  响应对象
     * @param dataList  数据列表
     * @param <T>   实体支持泛型
     */
    public static<T> void  xlsExport(String fileName, HttpServletResponse response, List<T> dataList)
    {
        if (CollectionUtils.isNullOrEmpty(dataList))
        {
            throw  new IllegalArgumentException("数据列表不能为空");
        }

        LinkedHashMap<String,String> headMap = Maps.newLinkedHashMap();
        try {
            Map<String, Object> objectMap = PropertyUtils.describe(dataList.get(0));
            if (CollectionUtils.isNotNullAndEmpty(objectMap))
            {
                for (String key: objectMap.keySet())
                {
                    headMap.put(key,key);
                }
            }
        } catch (Exception e) {
            logger.error("转换成map失败",e);
        }
        xlsExport(fileName,response,dataList,headMap);
    }

    /**
     * 不指定列头，按照实体的自然顺序展示
     * @param fileName  保存的xls文件名
     * @param response  响应对象
     * @param dataList  数据列表
     * @param  headMap  列title map
     * @param <T>   实体支持泛型
     */
    public static<T> void  xlsExport(String fileName, HttpServletResponse response, List<T> dataList, LinkedHashMap<String,String> headMap)
    {
        xlsExport(fileName,response,dataList,headMap,null,null);
    }

    /**
     * xls导出
     * @param fileName 文件名
     * @param response 响应对象
     * @param dataList 数据列表
     * @param headMap  头map
     * @param <T>  泛型
     */
    public static<T> void  xlsExport(String fileName, HttpServletResponse response, List<T> dataList, LinkedHashMap<String,String> headMap, String datetimeFormat, String dateFormat)
    {
        try {
            XlsTool xlsTool = new XlsTool(fileName);

            if (!Strings.isNullOrEmpty(dateFormat))
            {
                xlsTool.setDateFormat(dateFormat);
            }

            if (!Strings.isNullOrEmpty(datetimeFormat))
            {
                xlsTool.setDateTimeFormat(datetimeFormat);
            }

            String xlsFileName = getXlsFileName(fileName);
            wrapperResponse(response,xlsFileName);

            addXlsTitleRow(xlsTool,headMap);
            addContent(xlsTool,dataList,headMap);
            writeToSheet(xlsTool,response);
        } finally {
            //加速资源回收
            dataList = null;
            headMap = null;
        }


    }

    private static void writeToSheet(XlsTool xlsTool, HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            xlsTool.getWorkbook().write(outputStream);
            outputStream.flush();
        } catch (IOException e) {
            logger.error("写入内容到workbook异常",e);
        }finally {
            xlsTool.release();
            if (Objects.nonNull(outputStream))
            {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    logger.error("关闭输出流异常",e);
                }
            }
        }

    }

    private static <T> void addContent(XlsTool xlsTool, List<T> dataList, LinkedHashMap<String, String> headMap) {

        if (Objects.isNull(dataList) || dataList.isEmpty())
        {
            throw new IllegalArgumentException("数据列表不能为空");
        }

        for (int rowIndex=1;rowIndex<=dataList.size();rowIndex++)
        {
            HSSFRow row = xlsTool.getSheet().createRow(rowIndex);
            T entity = dataList.get(rowIndex - 1);
            int cellIndex=0;
            for (Map.Entry<String,String> entry: headMap.entrySet())
            {
                String key = entry.getKey();
                String propertyValue = getEntityPropertyValue(entity, key , xlsTool);

                HSSFCell cell = row.createCell(cellIndex++);

                HSSFRichTextString textString = new HSSFRichTextString(propertyValue);
                textString.applyFont(xlsTool.getFont());
                cell.setCellValue(textString);
            }

        }

    }

    private static <T> String getEntityPropertyValue(T entity, String key, XlsTool xlsTool) {

        String  stringValue = "";
        try {
            Object propertyValue = PropertyUtils.getProperty(entity, key);

            if (Objects.isNull(propertyValue)) {
                return stringValue;
            }

            if (propertyValue instanceof  Boolean)
            {
                stringValue = ((Boolean)propertyValue)?"是":"否";
            }else if (propertyValue instanceof LocalDateTime)
            {
                stringValue = ((LocalDateTime)propertyValue).format(DateTimeFormatter.ofPattern(xlsTool.getDateTimeFormat()));
            }else if (propertyValue instanceof Date)
            {
                stringValue = new SimpleDateFormat(xlsTool.getDateFormat()).format(((Date)propertyValue));
            }else if (propertyValue instanceof LocalDate)
            {
                stringValue = ((LocalDate)propertyValue).format(DateTimeFormatter.ofPattern(xlsTool.getDateFormat()));
            }else {
                stringValue = String.valueOf(propertyValue);
            }

        } catch (Exception e) {
           logger.error("获取属性异常，属性【{}】,实体：【{}】",key,entity);
        }
        return stringValue;
    }

    private static void addXlsTitleRow(XlsTool xlsTool,LinkedHashMap<String,String> headMap) {

        if (Objects.isNull(headMap) || headMap.isEmpty())
        {
            throw new IllegalArgumentException("头Map不能为空");
        }

        HSSFRow row = xlsTool.getSheet().createRow(0);

        int i=0;
        for (Map.Entry<String,String> entry: headMap.entrySet())
        {
            String title = entry.getValue();
            HSSFCell cell = row.createCell(i);
            HSSFRichTextString textString = new HSSFRichTextString(title);
            textString.applyFont(HSSFColor.BLACK.index);
            cell.setCellValue(textString);
            i++;
        }

    }

    private static void wrapperResponse(HttpServletResponse response, String fileName) {

        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

    }

    /**
     * 处理文件名
     * @param fileName
     * @return
     */
    private static String getXlsFileName(String fileName) {
        if (Strings.isNullOrEmpty(fileName))
        {
            throw  new IllegalArgumentException("导出的文件名不能为空");
        }
         fileName =  fileName.concat(".xls");
        try {
            fileName =  new String(fileName.getBytes("GBK"),"ISO8859_1");
        } catch (UnsupportedEncodingException e) {
            logger.error("文件名转码失败",e);
        }
        return fileName;
    }


}
